/**
* Copyright (c) By zengqh.
*
* This program is just for fun or demo, in the hope that it  
* will be useful, you can redistribute it and/or modify freely.
*
* Time: 2013/02/18
* File: rect.h
**/

#pragma once

#include "vector2.h"

namespace HY
{
	/// Two-dimensional bounding rectangle.
	class Rect
	{
	public:
		/// Construct an undefined rect.
		Rect() :
		  min_(Vector2::ZERO),
			  max_(Vector2::ZERO),
			  defined_(false)
		  {
		  }

		  /// Copy-construct from another rect.
		  Rect(const Rect& rect) :
		  min_(rect.min_),
			  max_(rect.max_),
			  defined_(rect.defined_)
		  {
		  }

		  /// Construct from minimum and maximum vectors.
		  Rect(const Vector2& min, const Vector2& max) :
		  min_(min),
			  max_(max),
			  defined_(true)
		  {
		  }

		  /// Construct from coordinates.
		  Rect(float left, float top, float right, float bottom) :
		  min_(left, top),
			  max_(right, bottom),
			  defined_(true)
		  {
		  }

		  /// Assign from another rect.
		  Rect& operator = (const Rect& rhs)
		  {
			  min_ = rhs.min_;
			  max_ = rhs.max_;
			  defined_ = rhs.defined_;
			  return *this;
		  }

		  /// Test for equality with another rect.
		  bool operator == (const Rect& rhs) const { return min_ == rhs.min_ && max_ == rhs.max_; }
		  /// Test for inequality with another rect.
		  bool operator != (const Rect& rhs) const { return min_ != rhs.min_ || max_ != rhs.max_; }

		  /// Define from another rect.
		  void Define(const Rect& rect)
		  {
			  min_ = rect.min_;
			  max_ = rect.max_;
			  defined_ = true;
		  }

		  /// Define from minimum and maximum vectors.
		  void Define(const Vector2& min, const Vector2& max)
		  {
			  min_ = min;
			  max_ = max;
			  defined_ = true;
		  }

		  /// Define from a point.
		  void Define(const Vector2& point)
		  {
			  min_ = max_ = point;
			  defined_ = true;
		  }

		  /// Merge a point.
		  void Merge(const Vector2& point)
		  {
			  if (!defined_)
			  {
				  min_ = max_ = point;
				  defined_ = true;
			  }

			  if (point.x_ < min_.x_)
				  min_.x_ = point.x_;
			  if (point.x_ > max_.x_)
				  max_.x_ = point.x_;
			  if (point.y_ < min_.y_)
				  min_.y_ = point.y_;
			  if (point.y_ > max_.y_)
				  max_.y_ = point.y_;
		  }

		  /// Merge a rect.
		  void Merge(const Rect& rect)
		  {
			  if (!defined_)
			  {
				  min_ = rect.min_;
				  max_ = rect.max_;
				  defined_ = true;
			  }

			  if (rect.min_.x_ < min_.x_)
				  min_.x_ = rect.min_.x_;
			  if (rect.min_.y_ < min_.y_)
				  min_.y_ = rect.min_.y_;
			  if (rect.max_.x_ > max_.x_)
				  max_.x_ = rect.max_.x_;
			  if (rect.max_.y_ > max_.y_)
				  max_.y_ = rect.max_.y_;
		  }

		  /// Clear to undefined state.
		  void Clear()
		  {
			  min_ = Vector2::ZERO;
			  max_ = Vector2::ZERO;
			  defined_ = false;
		  }

		  /// Clip with another rect.
		  void Clip(const Rect& rect);

		  /// Return center.
		  Vector2 Center() const { return (max_ + min_) * 0.5f; }
		  /// Return size.
		  Vector2 Size() const { return max_ - min_; }
		  /// Return half-size.
		  Vector2 HalfSize() const { return (max_ - min_) * 0.5f; }
		  /// Test for equality with another rect with epsilon.
		  bool Equals(const Rect& rhs) const { return min_.Equals(rhs.min_) && max_.Equals(rhs.max_); }

		  /// Return float data.
		  const void* Data() const { return &min_.x_; }

		  /// Minimum vector.
		  Vector2 min_;
		  /// Maximum vector.
		  Vector2 max_;
		  /// Defined flag.
		  bool defined_;

		  /// Rect in the range (-1, -1) - (1, 1)
		  static const Rect FULL;
		  /// Rect in the range (0, 0) - (1, 1)
		  static const Rect POSITIVE;
		  /// Zero-sized rect.
		  static const Rect ZERO;
	};

	/// Two-dimensional bounding rectangle with integer values.
	class IntRect
	{
	public:
		/// Construct an undefined rect.
		IntRect()
		{
		}

		/// Construct from coordinates.
		IntRect(int left, int top, int right, int bottom) :
		left_(left),
			top_(top),
			right_(right),
			bottom_(bottom)
		{
		}

		/// Test for equality with another rect.
		bool operator == (const IntRect& rhs) const { return left_ == rhs.left_ && top_ == rhs.top_ && right_ == rhs.right_ && bottom_ == rhs.bottom_; }
		/// Test for inequality with another rect.
		bool operator != (const IntRect& rhs) const { return left_ != rhs.left_ || top_ != rhs.top_ || right_ != rhs.right_ || bottom_ != rhs.bottom_; }

		/// Return size.
		IntVector2 Size() const { return IntVector2(Width(), Height()); }
		/// Return width.
		int Width() const { return right_ - left_; }
		/// Return height.
		int Height() const { return bottom_ - top_; }
		/// Return integer data.
		const int* Data() const { return &left_; }

		/// Left coordinate.
		int left_;
		/// Top coordinate.
		int top_;
		/// Right coordinate.
		int right_;
		/// Bottom coordinate.
		int bottom_;

		/// Zero-sized rect.
		static const IntRect ZERO;
	};


}